#include "stdafx.h"
#include "Triangle.h"

namespace PhotonMapping
{

Triangle::Triangle(const Math::Vector3& p_P0, const Math::Vector3& p_P1, const Math::Vector3& p_P2, intx p_MaterialId)
	: IObject(p_MaterialId), m_P0(p_P0), m_P1(p_P1), m_P2(p_P2)
{
	// calc normal
	m_Normal = Cross(m_P1 - m_P0, m_P2 - m_P0);
	m_Normal.Normalize();

	// todo: calc bounding sphere
}

// code from http://www.softsurfer.com/Archive/algorithm_0105/algorithm_0105.htm#Segment-Triangle
intx Triangle::TestIntersection(const Math::Ray& p_Ray, float &p_Distance)
{
	using namespace Math;

	Vector3   u, v;             // triangle vectors
	Vector3   w0;                // ray vectors
	float     r, a, b;             // params to calc ray-plane intersect

	// get triangle edge vectors and plane normal
	u = m_P1 - m_P0;
	v = m_P2 - m_P0;

	w0 = p_Ray.m_Position - m_P0;
	a = -(m_Normal * w0);
	b = (m_Normal * p_Ray.m_Direction);
	if(Abs(b) < EPSILON)	// ray is parallel to triangle plane
		return IObject::MISS;

	// get intersect point of ray with triangle plane
	r = a / b;
	// ray goes away from triangle or triangle is further away than p_Distance
	if(r < 0.0f || r >= p_Distance)
		return IObject::MISS;      // => no intersect

	// is I inside T?
	Vector3 I = p_Ray.m_Position + r * p_Ray.m_Direction;
	float    uu, uv, vv, wu, wv, D;
	uu = (u * u);
	uv = (u * v);
	vv = (v * v);
	Vector3 w = I - m_P0;
	wu = (w * u);
	wv = (w * v);
	D = uv * uv - uu * vv;

	// get and test parametric coords
	float s, t;
	s = (uv * wv - vv * wu) / D;
	if (s < 0.0 || s > 1.0)        // I is outside T
		return IObject::MISS;
	t = (uv * wu - uu * wv) / D;
	if (t < 0.0 || (s + t) > 1.0)  // I is outside T
		return IObject::MISS;

	p_Distance = r;
	return IObject::HIT;                      // I is in T
}

const Math::Sphere& Triangle::GetBoundingSphere() const
{
	return m_BoundingSphere;
}

const Math::Vector3 Triangle::GetNormalAt(const Math::Vector3& p_Pos)
{
	return m_Normal;
}

}

